#pragma once
#include <functional>
#include <mutex>
#include <string>
#include <unordered_map>

namespace cpp_component
{

template <typename T> class event
{
   public:
    event() = default;
    ~event() = default;
    using handler = typename std::unordered_multimap<std::string, std::function<T>>::iterator;
    template <typename... Args> void notify(const std::string &key, Args &&... args)
    {
        auto subscriber = m_subscribers.equal_range(key);

        if (subscriber.first != std::end(m_subscribers))
        {
            for (auto iter = subscriber.first; iter != subscriber.second; ++iter)
            {
                iter->second(std::forward<Args>(args)...);
            }
        }
    }

    handler subscribe(const std::string &key, const std::function<T> function)
    {
        std::lock_guard guard{mutex};
        return m_subscribers.emplace(key, function);
    }

    void unsubscribe(handler &iter)
    {
        std::lock_guard guard{mutex};
        if (iter != m_subscribers.end())
        {
            m_subscribers.erase(iter);
            iter = m_subscribers.end();
        }
    }

   private:
    std::mutex mutex;
    std::unordered_multimap<std::string, std::function<T>> m_subscribers;
};
}  // namespace cpp_component
